package com.sumer.brain.common.annotation;

import com.sumer.brain.common.config.JwtProperties;
import com.sumer.brain.common.constant.SystemConstant;
import com.sumer.brain.common.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * 实现HandlerMethodArgumentResolver接口，自定义解析器，用于解析JWT令牌中的用户ID。
 * 该解析器会从请求头中获取JWT令牌，并解析其中的用户ID，提供给控制器方法作为参数使用。
 */
@RequiredArgsConstructor
@Component
@Slf4j
public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {

    private final JwtProperties jwtProperties;

    /**
     * 判断当前解析器是否支持解析指定的方法参数。
     * 支持的情况是：方法参数上有@UserId注解。
     *
     * @param parameter 方法参数描述
     * @return 如果支持解析，返回true；否则返回false。
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 检查参数是否被@UserId注解
        return parameter.hasParameterAnnotation(UserId.class);
    }

    /**
     * 解析方法参数，从请求头中获取JWT令牌，并尝试解析用户ID。
     * 如果令牌不存在或解析失败，返回null。
     *
     * @param parameter     方法参数描述
     * @param mavContainer  ModelAndViewContainer，用于Web请求处理中的模型和视图容器，此处未使用。
     * @param webRequest    NativeWebRequest，表示一个Web请求的对象，用于获取请求头信息。
     * @param binderFactory WebDataBinderFactory，用于创建数据绑定器的工厂，此处未使用。
     * @return 解析出的用户ID，如果解析失败或令牌不存在，返回null。
     * @throws Exception 如果JWT解析过程中发生异常。
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        // 从请求头中获取JWT令牌
        String token = webRequest.getHeader(SystemConstant.ACCESS_TOKEN);
        // 如果令牌不存在或为空字符串，则直接返回null
        if (!StringUtils.hasText(token)) {
            return null;
        }
        // 移除令牌前缀
        token = token.replace(SystemConstant.TOKEN_PREFIX, "");
        try {
            // 使用JWT工具类和秘钥解析令牌
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
            // 获取令牌的主题，即用户ID
            String userid = claims.getSubject();
            // 如果用户ID存在且不为空字符串，则转换为Long类型返回，否则返回null
            if (StringUtils.hasText(userid)) {
                return Long.parseLong(userid);
            }
            return null;
        } catch (Exception e) {
            log.info("解析JWT令牌失败", e);
            // 解析失败，返回null
            return null;
        }
    }
}
